#include <stdio.h>
#include "innbbsconf.h"
#include "daemon.h"
#include "bbslib.h"
#include <time.h>

#define INNTOBBS
#include "inntobbs.h"
#include "lang.h"

#include "bbs.h"

#include "inn_funcs.h"

typedef struct Header {
    char *name;
    int id;
} header_t;

/*enum HeaderValue {
SUBJECT_H, FROM_H, DATE_H, MID_H, NEWSGROUPS_H,
NNTPPOSTINGHOST_H, NNTPHOST_H, CONTROL_H, PATH_H,
ORGANIZATION_H, LASTHEADER,
};
*/

/*char *strchr ARG((char*,int));
char *strrchr ARG((char*,int));
char *strstr ARG((char*,char*));
*/

header_t headertable[] = {
    {"Subject", SUBJECT_H},
    {"From", FROM_H},
    {"Date", DATE_H},
    {"Message-ID", MID_H},
    {"Newsgroups", NEWSGROUPS_H},
    {"NNTP-Posting-Host", NNTPPOSTINGHOST_H},
    {"NNTP-Host", NNTPHOST_H},
    {"Control", CONTROL_H},
    {"Path", PATH_H},
    {"Organization", ORGANIZATION_H},
    {"X-Auth-From", X_Auth_From_H},
    {"Approved", APPROVED_H},
    {"Distribution", DISTRIBUTION_H},
    {"Keywords", KEYWORDS_H},
    {"Summary", SUMMARY_H},
    {"References", REFERENCES_H}
};

char *HEADER[LASTHEADER];
char *BODY;
char *FROM, *SUBJECT, *SITE, *DATE, *POSTHOST, *NNTPHOST, *PATH, *GROUPS, *MSGID, *CONTROL;

int isexcluded(path1, nl)
char *path1;
nodelist_t *nl;
{
    char path2[1024];

    /*
     * path2 = (char*)mymalloc(strlen(nl->node) + 3); 
     */
    sprintf(path2, "!%.*s!", (int)(sizeof path2 - 3), nl->node);
    if (strstr(path1, path2) != NULL)
        return 1;
    if (nl->exclusion && *nl->exclusion) {
        char *exclude, *ptr;

        for (exclude = nl->exclusion, ptr = strchr(exclude, ','); exclude && *exclude; ptr = strchr(exclude, ',')) {
            if (ptr)
                *ptr = '\0';
            sprintf(path2, "!%.*s!", (int)(sizeof path2 - 3), exclude);
            if (strstr(path1, path2) != NULL)
                return 1;
            if (ptr) {
                *ptr = ',';
                exclude = ptr + 1;
            } else {
                break;
            }
        }
    }
    return 0;
}

void feedfplog(newsfeeds_t *nf, char *filepath, int type)
{
    char *path1;
    nodelist_t *nl;

    if (nf == NULL)
        return;
    if (nf->path != NULL) {
        char *ptr1, *ptr2;
        char savech;

        path1 = (char *) mymalloc(strlen(HEADER[PATH_H]) + 3);
        sprintf(path1, "!%s!", HEADER[PATH_H]);
        for (ptr1 = nf->path; ptr1 && *ptr1;) {
            for (; *ptr1 && isspace(*ptr1); ptr1++);
            if (!*ptr1)
                break;
            for (ptr2 = ptr1; *ptr2 && !isspace(*ptr2); ptr2++);
            savech = *ptr2;
            *ptr2 = '\0';
            /*
             * innbbsdlog("search node %s\n",ptr1);
             */
            nl = (nodelist_t *) search_nodelist_bynode(ptr1);
            /*
             * innbbsdlog("search node node %s, host %s fp
             * %d\n",nl->node, nl->host, nl->feedfp);
             */
            *ptr2 = savech;
            ptr1 = ptr2++;
            if (nl == NULL)
                continue;
            if (nl->feedfp == NULL)
                continue;
            if (isexcluded(path1, nl))
                continue;
            /*
             * path2 = (char*)mymalloc(strlen(nl->node) + 3);
             * sprintf(path2, "!%s!",nl->node); free(path2);
             */
            /*
             * innbbsdlog("path1 %s path2 %s\n",path1, path2);
             */
            /*
             * if (strstr(path1, path2) != NULL) return; 
             */
            /*
             * to conform to the bntplink batch file 
             */
            {
                char *slash = strrchr(filepath, '/');

                if (slash != NULL)
                    *slash = '\t';
                fprintf(nl->feedfp, "%s\t%s\t\t%s\t%s\t%c\t%s\t%s!%s\n", filepath == NULL ? "" : filepath, GROUPS, FROM, SUBJECT, type, MSGID, MYBBSID, HEADER[PATH_H]);
                if (slash != NULL)
                    *slash = '/';
            }
            fflush(nl->feedfp);
            if (savech == '\0')
                break;
        }
        free(path1);
    }
}

static FILE *bbsfeedsfp = NULL;
static int bbsfeedson = -1;

void init_bbsfeedsfp()
{
    if (bbsfeedsfp != NULL) {
        fclose(bbsfeedsfp);
        bbsfeedsfp = NULL;
    }
    bbsfeedson = -1;
}

void bbsfeedslog(char *filepath, int type)
{

    char datebuf[40];
    time_t now;

    if (bbsfeedson == 0)
        return;
    if (bbsfeedson == -1) {
        if (!isfile(BBSFEEDS)) {
            bbsfeedson = 0;
            return;
        }
        bbsfeedson = 1;
    }
    if (bbsfeedsfp == NULL) {
        bbsfeedsfp = fopen(BBSFEEDS, "a");
    }
    time(&now);
    strftime(datebuf, sizeof(datebuf), "%b %d %X ", localtime(&now));

    if (bbsfeedsfp != NULL) {
        fprintf(bbsfeedsfp, "%s %c %s %s %s %s!%s %s\n", datebuf, type, REMOTEHOSTNAME, GROUPS, MSGID, MYBBSID, HEADER[PATH_H], filepath == NULL ? "" : filepath);
        fflush(bbsfeedsfp);
    }
}

static FILE *echomailfp = NULL;
static int echomaillogon = -1;

void init_echomailfp()
{
    if (echomailfp != NULL) {
        fclose(echomailfp);
        echomailfp = NULL;
    }
    echomaillogon = -1;
}

void echomaillog()
{

    if (echomaillogon == 0)
        return;
    if (echomaillogon == -1) {
        if (!isfile(ECHOMAIL)) {
            echomaillogon = 0;
            return;
        }
        echomaillogon = 1;
    }
    if (echomailfp == NULL) {
        echomailfp = fopen(ECHOMAIL, "a");
    }
    if (echomailfp != NULL) {
        fprintf(echomailfp, "\n");
        fprintf(echomailfp, "%s%s, %s%s\n", FromTxt, FROM, BoardTxt, GROUPS);
        fprintf(echomailfp, "%s%s\n", SubjectTxt, SUBJECT);
        fprintf(echomailfp, "%s%s (%s)\n", OrganizationTxt, SITE, DATE);
        fprintf(echomailfp, "%s%s (%s)\n", PathTxt, PATH, REMOTEHOSTNAME);
        fflush(echomailfp);
    }
}

#ifdef FILTER

char *cmdfilter(indata, filterbuffer, cmd)
char *indata, **filterbuffer;
FuncPtr cmd;
{
    int len = strlen(indata);

    if (*filterbuffer != NULL)
        *filterbuffer = (char *) myrealloc(*filterbuffer, len + 4096);
    else
        *filterbuffer = (char *) mymalloc(len + 4096);
    if (filterbuffer == NULL)
        return NULL;
    bcopy(indata, *filterbuffer, len);
    (*cmd) (*filterbuffer, &len, 0, getSession());
    (*filterbuffer)[len] = '\0';
    return *filterbuffer;
}

char *externfilter(indata, filterbuffer, cmd)
char *indata, **filterbuffer, *cmd;
{
    FILE *fp;
    int fd;
    char *tmpfile;

    int len = strlen(indata);
    struct stat st;

    fp = (FILE *) popen((char *)
                        fileglue("%s > /tmp/.innbbsdfilter%d%d", cmd, getpid(), getuid()), "w");
    if (fp == NULL) {
        innbbsdlog("Err: can't popen %s\n", cmd);
        return NULL;
    }
    if (fwrite(indata, 1, len, fp) != len) {
        innbbsdlog("Err: fwrite to %s failed, len %d\n", cmd, len);
        return NULL;
    }
    pclose(fp);

    tmpfile = (char *) fileglue("/tmp/.innbbsdfilter%d%d", getpid(), getuid());
    if (stat(tmpfile, &st) != 0)
        return NULL;

    if (*filterbuffer != NULL)
        *filterbuffer = myrealloc(*filterbuffer, st.st_size + 1);
    else
        *filterbuffer = mymalloc(st.st_size + 1);
    (*filterbuffer)[st.st_size] = '\0';
    if (*filterbuffer == NULL)
        return NULL;

    fd = open(tmpfile, O_RDONLY);
    if (fd < 0)
        return NULL;
    read(fd, *filterbuffer, st.st_size);
    close(fd);
    unlink(tmpfile);
    return *filterbuffer;
}

char *filterdata(arp, direction, indata, filterdata)
newsfeeds_t *arp;
int direction;
char *indata, **filterdata;
{
    char *outdata;
    FuncPtr fptr = NULL;
    char *cmdptr = NULL;

    if (direction) {
        fptr = arp->sfilter;
        cmdptr = arp->scmdfilter;
    } else {
        fptr = arp->rfilter;
        cmdptr = arp->rcmdfilter;
    }
    if (fptr)
        outdata = cmdfilter(indata, filterdata, fptr);
    else if (cmdptr)
        outdata = externfilter(indata, filterdata, cmdptr);
    else
        outdata = NULL;
    return outdata;
}

char *processfilter(indata, filterbuffer, direction)
char *indata, **filterbuffer;
int direction;
{
    char *front = indata, *ptr, *hptr;
    char *outdata = indata;
    int filterflag = 0;

    for (ptr = (char *) strchr(indata, '\n'); ptr != NULL && *ptr != '\0'; front = ptr + 1, ptr = (char *) strchr(front, '\n')) {
        *ptr = '\0';
        if (front[0] == '\r' || front[1] == '\n') {
            *ptr = '\n';
            break;
        }
        hptr = (char *) strchr(front, ':');
        if (hptr != NULL && hptr[1] == ' ') {
            *hptr = '\0';
            if (strcmp(front, "Newsgroups") == 0) {
                char *ngp, *ongp;
                newsfeeds_t *arp;
                char *tp;

                if ((tp = (char *) strchr(hptr + 2, '\r')) != NULL)
                    *tp = '\0';
                for (ngp = hptr + 2, ongp = strchr(ngp, ','); ngp && *ngp; ongp = strchr(ngp, ',')) {
                    if (ongp)
                        *ongp = '\0';
                    arp = search_group(ngp);
                    if (arp) {
                        if (ongp)
                            *ongp = ',';
                        if (tp != NULL)
                            *tp = '\r';
                        if (hptr)
                            *hptr = ':';
                        if (ptr)
                            *ptr = '\n';
                        outdata = filterdata(arp, direction, indata, filterbuffer);
                        if (outdata)
                            filterflag = 1;
                        if (ongp)
                            *ongp = '\0';
                        if (tp != NULL)
                            tp = '\0';
                        if (hptr)
                            *hptr = '\0';
                        if (ptr)
                            *ptr = '\0';
                    }
                    if (ongp) {
                        *ongp = ',';
                        ngp = ongp + 1;
                    } else {
                        break;
                    }
                    if (filterflag)
                        break;
                }
                if (tp != NULL)
                    *tp = '\r';
                filterflag = 1;
            }
            *hptr = ':';
        }
        *ptr = '\n';
        if (filterflag)
            break;
    }
    if (outdata)
        return outdata;
    else
        return indata;
}
#endif

int headercmp(a, b)
header_t *a, *b;
{
    return strcasecmp(a->name, b->name);
}

void article_init()
{
    int i;
    static int article_inited = 0;

    if (article_inited)
        return;
    article_inited = 1;

    qsort(headertable, sizeof(headertable) / sizeof(header_t), sizeof(header_t), headercmp);
    for (i = 0; i < LASTHEADER; i++)
        HEADER[i] = NULL;
}

int headervalue(char *inputheader)
{
    header_t key, *findkey;
    static int hasinit = 0;

    if (hasinit == 0) {
        article_init();
        hasinit = 1;
    }
    key.name = inputheader;
    findkey = (header_t *) bsearch((char *) &key, (char *) headertable, sizeof(headertable) / sizeof(header_t), sizeof(key), headercmp);
    if (findkey != NULL)
        return findkey->id;
    return -1;
}


void readlines(ClientType *client)
{
    buffer_t *in = &client->in;
    char *indata = in->data;
    char *front = in->data, *ptr, *hptr;
    int i;

    for (i = 0; i < LASTHEADER; i++)
        HEADER[i] = NULL;

#ifdef FILTER
    indata = processfilter(in->data, &client->filter_buffer, 0);
#endif

    if (indata != NULL) {
        front = indata;
    } else {
        front = indata = in->data;
    }

    for (ptr = (char *) strchr(indata, '\n'); ptr != NULL && *ptr != '\0'; front = ptr + 1, ptr = (char *) strchr(front, '\n')) {
        *ptr = '\0';
        if (front[0] == '\r' || front[1] == '\n') {
            BODY = front + 2;
            break;
        }
        hptr = (char *) strchr(front, ':');
        if (hptr != NULL && hptr[1] == ' ') {
            int value;

            *hptr = '\0';
            value = headervalue(front);
            if (value != -1) {
                char *tp;

                HEADER[value] = hptr + 2;
                if ((tp = (char *) strchr(HEADER[value], '\r')) != NULL)
                    *tp = '\0';
            }
            *hptr = ':';
        }
                /**ptr = '\n';*/
    }
    NNTPHOST = HEADER[NNTPHOST_H];
    PATH = HEADER[PATH_H];
    FROM = HEADER[FROM_H];
    GROUPS = HEADER[NEWSGROUPS_H];
    SUBJECT = HEADER[SUBJECT_H];
    DATE = HEADER[DATE_H];
    SITE = HEADER[ORGANIZATION_H];
    MSGID = HEADER[MID_H];
    CONTROL = HEADER[CONTROL_H];
    POSTHOST = HEADER[NNTPPOSTINGHOST_H];
    if (POSTHOST == NULL) {
        if (HEADER[X_Auth_From_H] != NULL) {
            POSTHOST = HEADER[X_Auth_From_H];
            HEADER[NNTPPOSTINGHOST_H] = POSTHOST;
        }
    }
}



#ifdef INNTOBBS_MAIN
main()
{
    int i, j, k, l, m, n, o, p, q;

    article_init();
    i = headervalue("Subject");
    j = headervalue("From");
    k = headervalue("Date");
    l = headervalue("NNTP-Posting-Host");
    m = headervalue("Newsgroups");
    n = headervalue("Message-ID");
}
#endif
